package com.zlkj.pro.modular.business.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.file.modular.entity.SysFileInfo;
import cn.stylefeng.roses.kernel.file.modular.service.SysFileInfoService;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.system.api.pojo.user.SysUserDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.user.request.SysUserRequest;
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserService;
import com.anji.captcha.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zlkj.pro.core.consts.ProjectConstants;
import com.zlkj.pro.core.enums.CertificateStatusEnum;
import com.zlkj.pro.core.enums.MsgTemplateEnum;
import com.zlkj.pro.core.enums.ReportConferStatusEnum;
import com.zlkj.pro.core.enums.ReportStatusEnum;
import com.zlkj.pro.core.exception.BusinessException;
import com.zlkj.pro.core.util.ConvertUtil;
import com.zlkj.pro.modular.admin.entity.Config;
import com.zlkj.pro.modular.admin.service.ConfigService;
import com.zlkj.pro.modular.app.mapper.AppUserMapper;
import com.zlkj.pro.modular.business.entity.*;
import com.zlkj.pro.modular.business.mapper.ProductInfoMapper;
import com.zlkj.pro.modular.business.mapper.ReportMapper;
import com.zlkj.pro.modular.business.mapper.ReportProductMapper;
import com.zlkj.pro.modular.business.model.dto.AreaDTO;
import com.zlkj.pro.modular.business.model.dto.ReportDTO;
import com.zlkj.pro.modular.business.model.dto.ReportProductDTO;
import com.zlkj.pro.modular.business.model.vo.*;
import com.zlkj.pro.modular.business.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.zlkj.pro.core.exception.enums.BusinessExceptionEnum.BUSINESS_EXCEPTION;

/**
 * @author liyang
 * @date 2024/4/6
 * @time 14:34
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ReportServiceImpl extends ServiceImpl<ReportMapper, ReportEntity> implements ReportService {


    @Autowired
    private ReportMapper reportMapper;

    @Autowired
    private AppUserMapper appUserMapper;

    @Autowired
    private TCustomerService customerService;

    @Autowired
    private ProductInfoMapper productInfoMapper;

    @Autowired
    private CustomerContactsService customerContactsService;

    @Autowired
    private Environment env;

    @Resource
    ConfigService configService;
    @Autowired
    private ReportProductMapper reportProductMapper;

    @Autowired
    private ReportProductService reportProductService;

    @Autowired
    private ReportDelayFileService reportDelayFileService;

    @Autowired
    private ReportFlowService reportFlowService;

    @Autowired
    private SysFileInfoService sysFileInfoService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private MessageService messageService;

    @Autowired
    private AgentService agentService;

    @Autowired
    private AreaService areaService;

    @Override
    public List<ReportVO> findList(ReportDTO dto) {

        if (dto.getUserId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");

        // 查询个人代理商信息
        AgentVO vo = appUserMapper.getAgentInfo(dto.getUserId());
        dto.setAgentId(vo.getId());


        // 角色赋值
        extracted(dto);
        if (dto.getRoleId() != 4) {
            dto.setQueryType(1);// 非经理按权限查询
        }

        List<ReportVO> reportVOList = reportMapper.findList(dto);

        // 设置动态配置
        List<Config> configs = findConfig();
        //报备有效期提前展示延期按钮天数
        int REPORT_END_BUTTON = Integer.parseInt(configs.stream().filter(c -> c.getCode().equals("REPORT_END_BUTTON")).findFirst().get().getValue());
        // 报备有效期提前提醒天数
        int REPORT_END_REMIND = Integer.parseInt(configs.stream().filter(c -> c.getCode().equals("REPORT_END_REMIND")).findFirst().get().getValue());


        extracted(dto);
        List<Long> ourUserIds = reportMapper.queryOurUserIds(dto.getUserId());

        reportVOList.forEach(reportVO -> {
            // 判断是否该展示申请延期按钮
            reportVO.setIsShowDelay(
                    !reportVO.getConferStatus().equals(ReportConferStatusEnum.REFUSE.getCode())
                    && reportVO.getExpirationDateEnd() != null
                    && (reportVO.getExpirationDateEnd().minusDays(REPORT_END_BUTTON).isBefore(LocalDate.now())
                    || reportVO.getExpirationDateEnd().minusDays(REPORT_END_BUTTON).isEqual(LocalDate.now()))
                    && Objects.equals(reportVO.getConferStatus(), ReportConferStatusEnum.CONFERING.getCode()));
            // 判断是否该延期提醒
            if (reportVO.getStatus().equals(ReportStatusEnum.CONFER.getCode())) {
                reportVO.setIsAlarm(reportVO.getExpirationDateEnd() != null
                        && (reportVO.getExpirationDateEnd().minusDays(REPORT_END_REMIND).isBefore(LocalDate.now())
                        || reportVO.getExpirationDateEnd().minusDays(REPORT_END_REMIND).isEqual(LocalDate.now())));
            } else {
                reportVO.setIsAlarm(false);
            }

            if (dto.getRoleId() == 4) {
                // 添加是否是自己或者自己下属创建但报备单标识
                reportVO.setOurReport(ourUserIds.contains(reportVO.getCreateUser()));
            } else {
                reportVO.setOurReport(true);
            }
        });

        // 分页处理
        if (dto.getPageNum() != null && dto.getPageSize() != null) {
            reportVOList = reportVOList.stream().skip((dto.getPageNum() - 1) * dto.getPageSize()).limit(dto.getPageSize()).collect(Collectors.toList());
        }
        // 截取前20条记录
        /*if(CollectionUtils.isNotEmpty(reportVOList) && reportVOList.size() > 20){
            reportVOList = reportVOList.stream().limit(20).collect(Collectors.toList());
        }*/
        return reportVOList;
    }


    @Override
    public Map<String, Object> countReports(ReportDTO dto) {
        if (dto.getUserId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        Map<String, Object> map = new HashMap<>();
        dto.setStatus(1);
        map.put(String.valueOf(dto.getStatus()), reportMapper.reportCount(dto));
        dto.setStatus(2);
        map.put(String.valueOf(dto.getStatus()), reportMapper.reportCount(dto));
        dto.setStatus(3);
        dto.setCertificateStatus(1);// 只查询待登记数量
        map.put(String.valueOf(dto.getStatus()), reportMapper.reportCount(dto));
        dto.setStatus(4);
        dto.setCertificateStatus(null);
        map.put(String.valueOf(dto.getStatus()), reportMapper.reportCount(dto));
        return map;
    }


    @Override
    public List<Config> findConfig() {
        LambdaQueryWrapper<Config> queryWrapper = new LambdaQueryWrapper<Config>();
        List<String> codes = new ArrayList<>();
        codes.add("REPORT_END_BUTTON");
        codes.add("REPORT_DELAY_DAYS");
        codes.add("REPORT_END_REMIND");
        codes.add("REPORT_TIME_SERIES");
        codes.add("SAME_AGENT_DIFF_DAYS");
        queryWrapper
                .in(Config::getCode, codes)
                .eq(Config::getDelFlag, YesOrNotEnum.N.getCode());
        return configService.list(queryWrapper);
    }

    SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); // 设置格式模式
    DateTimeFormatter localDateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 设置格式模式

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public boolean add(ReportDTO dto) {
        if (dto.getUserId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        if (dto.getCustomerId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "customerId不能为空");
        if (dto.getCustomerContactsId() == null)
            throw new BusinessException(BUSINESS_EXCEPTION, "customerContactsId不能为空");
        if (dto.getExpirationDateStart() == null)
            throw new BusinessException(BUSINESS_EXCEPTION, "expirationDateStart不能为空");
        if (dto.getExpirationDateEnd() == null)
            throw new BusinessException(BUSINESS_EXCEPTION, "expirationDateEnd不能为空");
        if (CollectionUtils.isEmpty(dto.getProducts()))
            throw new BusinessException(BUSINESS_EXCEPTION, "products不能为空");


        // 校验当前客户，是否存在报备申请，若存在则提示不可发起
        Boolean customerHasReport = checkCustomerHasReport(dto.getCustomerId());
        if (customerHasReport)
            throw new BusinessException(BUSINESS_EXCEPTION, "客户存在报备中的报备单，不可发起新报备！");

        // 获取所在代理商信息
        AgentVO agent = appUserMapper.getAgentInfo(dto.getUserId());
        dto.setAgentId(agent.getId());
        dto.setCreateUser(dto.getUserId());// 当前登录人作为创建人
        ReportEntity report = ConvertUtil.turn(dto, ReportEntity.class);
        // 生成报备单编码
        report.setCode(getNextReportCode());
        report.setUpdateTime(new Date());

        // 补充客户信息
        CustomerEntity customerEntity = customerService.getById(dto.getCustomerId());
        report.setCustomerId(customerEntity.getId());
        report.setCustomerName(customerEntity.getName());
        report.setCustomerType(customerEntity.getType());
        report.setCustomerClassify(customerEntity.getClassify());
        report.setCustomerAddress(customerEntity.getAddress());
        report.setCustomerAddressDetail(customerEntity.getAddressDetail());
        report.setCustomerLevel(customerEntity.getLevel());
        report.setCustomerStatus(customerEntity.getCustomerStatus());
        report.setCustomerUscc(customerEntity.getUscc());
        report.setCustomerRemark(customerEntity.getRemark());
        report.setCustomerPhone(customerEntity.getPhone());

        // 补充联系人信息
        CustomerContactsEntity contacts = customerContactsService.getById(dto.getCustomerContactsId());
        report.setCustomerContactsName(contacts.getName());
        report.setCustomerContactsPhone(contacts.getPhone());

        // 计算审批截止日期
        LambdaQueryWrapper<Config> queryWrapper = new LambdaQueryWrapper<Config>();
        queryWrapper
                .eq(Config::getCode, "REPORT_APPLY_DAYS")// 报备审批时长
                .eq(Config::getDelFlag, YesOrNotEnum.N.getCode());
        Config config = configService.getOne(queryWrapper);
        String reportApplyDays = config.getValue();

        // 计算expirationDateEnd 加reportApplyDays之后的日期转换成localDate
        report.setApplyEndDate(report.getExpirationDateEnd().plusDays(Integer.parseInt(reportApplyDays)));

        // 自动审批通过逻辑
        Integer autoPassStatus = autoApprove(report, contacts, customerEntity, agent);
        // 校验当前客户，是否存在客户商谈中，若存在则提示不可发起
        if (autoPassStatus == 2) {
            if (checkCustomerHasReport2(dto.getCustomerId()))
                throw new BusinessException(BUSINESS_EXCEPTION, "客户存在商谈中的报备单，不可发起此次报备！");
        }
        super.save(report);
        Long reportId = report.getId();

        // 提交审批审批日志
        reportFlowService.addFlow(report.getId(), "申请报备", "代理商[" + sysUserService.getById(report.getCreateUser()).getRealName() + "]发起了报备", 1);
        // 发送消息
        messageService.sendMessage(MsgTemplateEnum.A,
                report.getId(),
                null,
                Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                dateFormatter.format(report.getCreateTime()))
                        .collect(Collectors.toList()),
                "申请成功，BMSH审批中。");


        if (autoPassStatus == 2) {
            // 自动通过审批日志
            reportFlowService.addFlow(report.getId(), "客户商谈中", "客户[" + report.getCustomerName() + "]正在与代理商谈", 1);
            // 发送消息
            messageService.sendMessage(MsgTemplateEnum.B,
                    report.getId(),
                    null,
                    Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                    localDateFormatter.format(report.getExpirationDateEnd()))
                            .collect(Collectors.toList()),
                    "通过");
        } else if (autoPassStatus == 4) {
            // 发送全部校验失败驳回通知 审批日志
            reportFlowService.addFlow(report.getId(), "审核未通过", "自动审核全部未通过驳回", 2);
            // 发送消息
            messageService.sendMessage(MsgTemplateEnum.C,
                    report.getId(),
                    null,
                    Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                    localDateFormatter.format(report.getExpirationDateEnd()))
                            .collect(Collectors.toList()),
                    "驳回(" + "自动审核全部未通过驳回" + ")");
        }

        // 添加产品信息
        List<Long> productIds = dto.getProducts().stream().map(ReportProductDTO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(productIds)) {
            List<ProductInfoEntity> products = productInfoMapper.selectBatchIds(productIds);
            List<ReportProductEntity> productList = new ArrayList<>(products.size());
            products.forEach(p -> {
                ReportProductEntity product = new ReportProductEntity();
                product.setId(null);
                product.setReportId(reportId);
                product.setCode(p.getCode());
                product.setProductId(p.getId());
                product.setProductTypeId(p.getProductTypeId());
                product.setName(p.getName());
                product.setPrice(p.getPrice());
                product.setIntroduce(p.getIntroduce());
                product.setImageDetailFileId(p.getImageDetailFileId());
                product.setRemark(p.getRemark());
                product.setManualFileId(p.getManualFileId());
                product.setCreateUser(dto.getUserId());
                product.setNumber(dto.getProducts().stream().filter(t -> t.getId().equals(p.getId())).findFirst().get().getNumber());
                productList.add(product);
            });
            // 批量设置书名号前缀
            // setCertificateCode(agent, productList);
            // 批量保存产品快照信息
            reportProductService.saveBatch(productList);
        }
        return true;
    }

    private Boolean checkCustomerHasReport(Long customerId) {
        // 获取报备单产品信息
        LambdaQueryWrapper<ReportEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ReportEntity::getCustomerId, customerId);
        queryWrapper.eq(ReportEntity::getDelFlag, "N");
        List<Integer> status = new ArrayList<>();
        status.add(1);
        queryWrapper.in(ReportEntity::getStatus, status);
        List<ReportEntity> reports = this.list(queryWrapper);
        return CollectionUtils.isNotEmpty(reports);
    }

    private Boolean checkCustomerHasReport2(Long customerId) {
        // 获取报备单产品信息
        LambdaQueryWrapper<ReportEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ReportEntity::getCustomerId, customerId);
        queryWrapper.eq(ReportEntity::getDelFlag, "N");
        List<Integer> status = new ArrayList<>();
        status.add(2);
        queryWrapper.in(ReportEntity::getStatus, status);
        List<ReportEntity> reports = this.list(queryWrapper);
        return CollectionUtils.isNotEmpty(reports);
    }

    // 批量设置书名号前缀
    private void setCertificateCode(AgentVO agent, List<ReportProductEntity> productList) {
        StringBuilder pinyin;
        String pre = filterChineseAndEnglish(agent.getName());
        // 判断是否有重名的代理商，如果有按创建时间排序添加 01 02 03 序号再在四位拼音之后
        String repeatAgentNameNo = getRepeatAgentNameNo(agent.getId(), agent.getName());

        if (StringUtils.isEmpty(pre)) {
            // 没有任何中文和英文默认用BMSH做前缀
            pinyin = new StringBuilder("BMSH");
        } else {
            pinyin = new StringBuilder(pre);
            // 如果pre的长度不足4位用A补齐四位
            while (pinyin.length() < 4) {
                pinyin.append("A");
            }
        }

        // 预制书名号
        Integer cerNumber = agent.getCerNumber(); // 获取当前代理商cerNumber
        for (int i = 1; i <= productList.size(); i++) {
            // 将i转化为两位数前面补0
            String number = String.format("%06d", cerNumber + i);
            // 代理商名称转
            String certificateCode = pinyin + repeatAgentNameNo + "-" + LocalDate.now().getYear() + "-" + number;
            productList.get(i - 1).setCertificateCode(certificateCode);
        }
        // 更新cerNumber
        agentService.update(new UpdateWrapper<AgentEntity>().lambda().set(AgentEntity::getCerNumber, cerNumber + productList.size()).eq(AgentEntity::getId, agent.getId()));
    }

    private String getRepeatAgentNameNo(Long agentId, String agentName) {
        LambdaQueryWrapper<AgentEntity> queryWrapper = Wrappers.lambdaQuery();
        // 查询name = agentName的代理商
        queryWrapper.eq(AgentEntity::getName, agentName);
        // 按创建时间排序
        queryWrapper.orderByAsc(AgentEntity::getCreateTime);
        List<AgentEntity> list = agentService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            // 只有一个说明没有重复名称的代理商
            /*if (list.size() == 1) {
                return "";
            }*/
            // 遍历list找到id = agentId的元素，并返回它的index
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getId().equals(agentId)) {
                    // 否则返回i-1的元素的index
                    return String.format("%02d", i + 1);
                }
            }
        }
        return "";
    }

    /**
     * 将中文字符串转换成拼音首字母
     *
     * @param chinese 待转换的中文字符串
     * @return 拼音首字母字符串
     */
    public static String toPinyinAbbr(String chinese) {
        StringBuilder result = new StringBuilder();
        for (char c : chinese.toCharArray()) {
            if (c > 128) {
                String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
                if (pinyinArray != null && pinyinArray.length > 0) {
                    result.append(pinyinArray[0].charAt(0));
                }
            } else {
                result.append(c);
            }
        }
        return result.toString().toUpperCase();
    }

    /**
     * 筛选字符串中的中文字符
     *
     * @param source 源字符串
     * @return 只包含中文字符的新字符串
     */
    public static String filterChineseAndEnglish(String source) {

        StringBuilder pre = new StringBuilder();

        // 遍历String source的每一个字符串
        if (StringUtils.isEmpty(source)) return "";
        source = source.replaceAll(" ", "");// 去掉空格
        if (StringUtils.isEmpty(source)) return "";

        for (int i = 0; i < source.length() && i < 4; i++) {
            char c = source.charAt(i);
            if (isChinese(c)) {
                //字符是中文转拼音首字母
                pre.append(toPinyinAbbr(String.valueOf(c)));
            } else if (isEnglishLetter(c)) {
                // 英文字母转大写添加
                pre.append(String.valueOf(c).toUpperCase());
            }
        }
        return String.valueOf(pre);
    }

    private static boolean isChinese(char c) {
        Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
        return block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                // 可能还有其他CJK扩展块，根据需要添加
                ;
    }

    private static boolean isEnglishLetter(char c) {
        return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
    }

    // 代理商外失败原因
    private final String[] outFail = new String[]{"4", "3", "6", "9", "1", "2", "7"};
    // 代理商内失败原因
    private final String[] inFail = new String[]{"14", "13", "16", "19", "11", "12"};


    // 自动审批逻辑
    private Integer autoApprove(ReportEntity report, CustomerContactsEntity contacts, CustomerEntity customer, AgentVO agent) {
        String whyAutoFail = "";

        int outCheckCount = 0;
        int inCheckCount = 0;


        if (report.getCustomerType() == 1) {
            // 客户名称(企业客户)
            LambdaQueryWrapper<ReportEntity> queryWrapper4 = getQueryWrapper(report);
            queryWrapper4.eq(ReportEntity::getCustomerName, report.getCustomerName());
            // 查询报备单列表
            if (fixFailCodes(report, queryWrapper4, 4) > 0) {
                whyAutoFail = whyAutoFail + "4,";
            }
            outCheckCount = outCheckCount + 1;// 检查项目计数

            // 客户社会信用代码(企业客户)
            LambdaQueryWrapper<ReportEntity> queryWrapper3 = getQueryWrapper(report);
            queryWrapper3.eq(ReportEntity::getCustomerUscc, report.getCustomerUscc());
            if (fixFailCodes(report, queryWrapper3, 3) > 0) {
                whyAutoFail = whyAutoFail + "3,";
            }
            outCheckCount = outCheckCount + 1;// 检查项目计数
        }

        // 客户地址
        LambdaQueryWrapper<ReportEntity> queryWrapper6 = getQueryWrapper(report);
        queryWrapper6.eq(ReportEntity::getCustomerAddress, report.getCustomerAddress());
        if (fixFailCodes(report, queryWrapper6, 6) > 0) {
            whyAutoFail = whyAutoFail + "6,";
        }
        outCheckCount = outCheckCount + 1;// 检查项目计数

        // 客户详细地址
        LambdaQueryWrapper<ReportEntity> queryWrapper9 = getQueryWrapper(report);
        queryWrapper9.eq(ReportEntity::getCustomerAddressDetail, report.getCustomerAddressDetail());
        if (fixFailCodes(report, queryWrapper9, 9) > 0) {
            whyAutoFail = whyAutoFail + "9,";
        }
        outCheckCount = outCheckCount + 1;// 检查项目计数

        // 客户联系人
        LambdaQueryWrapper<ReportEntity> queryWrapper1 = getQueryWrapper(report);
        queryWrapper1.eq(ReportEntity::getCustomerContactsName, report.getCustomerContactsName());
        if (fixFailCodes(report, queryWrapper1, 1) > 0) {
            whyAutoFail = whyAutoFail + "1,";
        }
        outCheckCount = outCheckCount + 1;// 检查项目计数

        // 客户联系人电话
        LambdaQueryWrapper<ReportEntity> queryWrapper2 = getQueryWrapper(report);
        queryWrapper2.eq(ReportEntity::getCustomerContactsPhone, report.getCustomerContactsPhone());
        if (fixFailCodes(report, queryWrapper2, 2) > 0) {
            whyAutoFail = whyAutoFail + "2,";
        }
        outCheckCount = outCheckCount + 1;// 检查项目计数

        // 销售区域
        AreaDTO dto = new AreaDTO();// 获取共享区域
        dto.setSharing(1);
        List<AreaVO> areas = areaService.findList(dto);
        // 从areas中收集name
        List<String> sharingAreas = areas.stream().map(AreaVO::getName).collect(Collectors.toList());

        if (!agent.getArea().contains(customer.getProvince())
                && !sharingAreas.contains(customer.getProvince())) {
            whyAutoFail = whyAutoFail + "7,";
        }
        outCheckCount = outCheckCount + 1;// 检查项目计数

        // --------------代理商内部检查逻辑新增 -20240830----------start--------
        if (report.getCustomerType() == 1) {
            // 客户名称(企业客户)
            LambdaQueryWrapper<ReportEntity> queryWrapper14 = getQueryWrapperIn(report);
            queryWrapper14.eq(ReportEntity::getCustomerName, report.getCustomerName());
            // 查询报备单列表
            if (fixFailCodes(report, queryWrapper14,14) > 0) {
                whyAutoFail = whyAutoFail + "14,";
            }
            inCheckCount = inCheckCount + 1;// 检查项目计数

            // 客户社会信用代码(企业客户)
            LambdaQueryWrapper<ReportEntity> queryWrapper13 = getQueryWrapperIn(report);
            queryWrapper13.eq(ReportEntity::getCustomerUscc, report.getCustomerUscc());
            if (fixFailCodes(report, queryWrapper13, 13) > 0) {
                whyAutoFail = whyAutoFail + "13,";
            }
            inCheckCount = inCheckCount + 1;// 检查项目计数
        }

        // 客户地址
        LambdaQueryWrapper<ReportEntity> queryWrapper16 = getQueryWrapperIn(report);
        queryWrapper16.eq(ReportEntity::getCustomerAddress, report.getCustomerAddress());
        if (fixFailCodes(report, queryWrapper16, 16) > 0) {
            whyAutoFail = whyAutoFail + "16,";
        }
        inCheckCount = inCheckCount + 1;// 检查项目计数

        // 客户详细地址
        LambdaQueryWrapper<ReportEntity> queryWrapper19 = getQueryWrapperIn(report);
        queryWrapper19.eq(ReportEntity::getCustomerAddressDetail, report.getCustomerAddressDetail());
        if (fixFailCodes(report, queryWrapper19, 19) > 0) {
            whyAutoFail = whyAutoFail + "19,";
        }
        inCheckCount = inCheckCount + 1;// 检查项目计数

        // 客户联系人
        LambdaQueryWrapper<ReportEntity> queryWrapper11 = getQueryWrapperIn(report);
        queryWrapper11.eq(ReportEntity::getCustomerContactsName, report.getCustomerContactsName());
        if (fixFailCodes(report, queryWrapper11, 11) > 0) {
            whyAutoFail = whyAutoFail + "11,";
        }
        inCheckCount = inCheckCount + 1;// 检查项目计数

        // 客户联系人电话
        LambdaQueryWrapper<ReportEntity> queryWrapper12 = getQueryWrapperIn(report);
        queryWrapper12.eq(ReportEntity::getCustomerContactsPhone, report.getCustomerContactsPhone());
        if (fixFailCodes(report, queryWrapper12, 12) > 0) {
            whyAutoFail = whyAutoFail + "12,";
        }
        inCheckCount = inCheckCount + 1;// 检查项目计数


        // --------------代理商内部检查逻辑新增 -20240830----------end----------

        // 外部不符合项目计数
        int outCount = countCommonElements(whyAutoFail, outFail);
        // 内部不符合项目计数
        int inCount = countCommonElements(whyAutoFail, inFail);

        if (StringUtils.isEmpty(whyAutoFail)) {// 外、内 都全部通过 - 通过
            // 成交客户自动审批通过
            report.setStatus(ReportStatusEnum.CONFER.getCode());
            report.setApproveDate(LocalDate.now());
            return 2;// 审批通过
        } else if (outCount == outCheckCount || inCount == inCheckCount) { // 外、内 有一个全不符合 - 驳回
            // 删除whyAutoFail最后一个字符
            whyAutoFail = whyAutoFail.substring(0, whyAutoFail.length() - 1);
            report.setWhyAutoFail(whyAutoFail);
            report.setStatus(ReportStatusEnum.FAIL.getCode());
            report.setInvalidSource("自动审核未通过");
            report.setInvalidReason("自动审核未通过");
            return 4;//驳回
        } else {// 其他情况审批中
            // 删除whyAutoFail最后一个字符
            whyAutoFail = whyAutoFail.substring(0, whyAutoFail.length() - 1);
            report.setWhyAutoFail(whyAutoFail);
            return 1;//审批中
        }

        // 如果全部校验不通过 直接驳回
        /*if (allFail) {
            // 删除whyAutoFail最后一个字符
            whyAutoFail = whyAutoFail.substring(0, whyAutoFail.length() - 1);
            report.setWhyAutoFail(whyAutoFail);
            report.setStatus(ReportStatusEnum.FAIL.getCode());
            report.setInvalidSource("自动审核未通过");
            report.setInvalidReason("自动审核未通过");
            return 4;//驳回
        } else if (StringUtils.isNotEmpty(whyAutoFail)) {
            // 删除whyAutoFail最后一个字符
            whyAutoFail = whyAutoFail.substring(0, whyAutoFail.length() - 1);
            report.setWhyAutoFail(whyAutoFail);
            return 1;//审批中
        } else {
            // 成交客户自动审批通过
            report.setStatus(ReportStatusEnum.CONFER.getCode());
            report.setApproveDate(LocalDate.now());
            return 2;// 审批通过
        }*/
    }
    private static int countCommonElements(String whyAutoFail, String[] outFail) {
        if (StringUtils.isEmpty(whyAutoFail)) return 0;
        // 将 whyAutoFail 字符串按逗号分割成数组
        String[] failNumbers = whyAutoFail.split(",");
        // 将 outFail 数组转换为 HashSet 以提高查找速度
        Set<String> outFailSet = new HashSet<>(Arrays.asList(outFail));
        // 统计重复元素的数量
        int count = 0;
        for (String number : failNumbers) {
            if (outFailSet.contains(number)) {
                count++;
            }
        }
        return count;
    }

    /**
     * 查询该项目有多少个不合适的报备单
     *
     * @param report
     * @param queryWrapper
     * @return
     */
    private Integer fixFailCodes(ReportEntity report, LambdaQueryWrapper<ReportEntity> queryWrapper, Integer failNumber) {

        // 查询有多少个冲突的报备单
        List<ReportEntity> reports = super.list(queryWrapper);
        if (CollectionUtils.isEmpty(reports)) {
            return 0;
        } else {
            // 收集所有的报备单code
            List<String> codes = reports.stream().map(ReportEntity::getCode).collect(Collectors.toList());
            // 如果超过三个保留前三个
            if (codes.size() > 3) {
                codes = codes.subList(0, 3);
            }
            // 将codes转化成一个<br>分隔的字符串
            String failCodes = org.apache.commons.lang3.StringUtils.join(codes, "<br>");
            // 根据failNumber的值4 3 6 9 1 2 分别设置报备单的failCodes
            switch (failNumber) {
                case 4:
                    report.setFailCodes4(failCodes);
                    break;
                case 3:
                    report.setFailCodes3(failCodes);
                    break;
                case 6:
                    report.setFailCodes6(failCodes);
                    break;
                case 9:
                    report.setFailCodes9(failCodes);
                    break;
                case 1:
                    report.setFailCodes1(failCodes);
                    break;
                case 2:
                    report.setFailCodes2(failCodes);
                    break;
                case 14:
                    report.setFailCodes14(failCodes);
                    break;
                case 13:
                    report.setFailCodes13(failCodes);
                    break;
                case 16:
                    report.setFailCodes16(failCodes);
                    break;
                case 19:
                    report.setFailCodes19(failCodes);
                    break;
                case 11:
                    report.setFailCodes11(failCodes);
                    break;
                case 12:
                    report.setFailCodes12(failCodes);
                    break;
            }
            return reports.size();
        }
    }


    /**
     * 校验的公共queryWrapper
     *
     * @param report
     * @return
     */
    private static LambdaQueryWrapper<ReportEntity> getQueryWrapper(ReportEntity report) {
        // 查询其他代理商的报备单数量
        LambdaQueryWrapper<ReportEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.ne(ReportEntity::getAgentId, report.getAgentId());// 其他代理商
        queryWrapper.eq(ReportEntity::getDelFlag, "N");// 未删除的
        queryWrapper.in(ReportEntity::getStatus, 1, 2, 3); //报备中的（审核中、商谈中、待登记证明书号）三种状态的
//        queryWrapper.ne(ReportEntity::getCertificateStatus, CertificateStatusEnum.YES);
        return queryWrapper;
    }

    private LambdaQueryWrapper<ReportEntity> getQueryWrapperIn(ReportEntity report) {

        // 设置动态配置
        List<Config> configs = findConfig();
        //报备有效期提前展示延期按钮天数
        int SAME_AGENT_DIFF_DAYS = Integer.parseInt(configs.stream().filter(c -> c.getCode().equals("SAME_AGENT_DIFF_DAYS")).findFirst().get().getValue());

        LocalDate now = LocalDate.now();
        LocalDate ninetyDaysAgo = now.minusDays(SAME_AGENT_DIFF_DAYS);
        Date dateNinetyDaysAgo = Date.from(ninetyDaysAgo.atStartOfDay(ZoneId.systemDefault()).toInstant());
        LocalDate now2 = LocalDate.now();
        LocalDate afterDay = now2.plusDays(1);
        Date afterDays = Date.from(afterDay.atStartOfDay(ZoneId.systemDefault()).toInstant());

        // 查询其他代理商的报备单数量
        LambdaQueryWrapper<ReportEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ReportEntity::getAgentId, report.getAgentId());// 本代理商
        queryWrapper.eq(ReportEntity::getDelFlag, "N");// 未删除的
        //报备中、商谈中 或 过去90天内失效的数据
        queryWrapper.and(wrapper ->
                wrapper.in(ReportEntity::getStatus, ReportStatusEnum.APPLYING.getCode(), ReportStatusEnum.CONFER.getCode())
                        .or(
                                w -> w.between(ReportEntity::getUpdateTime, dateNinetyDaysAgo, afterDays)
                                        .and(w2 -> w2.eq(ReportEntity::getStatus, ReportStatusEnum.FAIL.getCode()))
                        )
        );
        return queryWrapper;
    }

    /**
     * 成交确认
     */
    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public boolean confirm(ReportDTO dto) {
        if (dto.getUserId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        if (dto.getId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "id不能为空");
        if (CollectionUtils.isEmpty(dto.getProducts()))
            throw new BusinessException(BUSINESS_EXCEPTION, "products不能为空");
        if (dto.getIsApprove() == null) throw new BusinessException(BUSINESS_EXCEPTION, "isApprove不能为空");

        // 获取当前报备单信息
        ReportEntity report = super.getById(dto.getId());
        if (!Objects.equals(ReportStatusEnum.CONFER.getCode(), report.getStatus())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单状态不在客户商谈中!");
        }
        /*if (Objects.equals(ReportConferStatusEnum.APPLYING.getCode(), report.getConferStatus())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单延期审批中,请勿重复提交申请!");
        }
        if (Objects.equals(ReportConferStatusEnum.DELAY.getCode(), report.getConferStatus())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单已延期，不可再次延期!");
        }*/
        if (!dto.getIsApprove()) {
            if (StringUtils.isEmpty(dto.getInvalidReason())) {
                throw new BusinessException(BUSINESS_EXCEPTION, "invalidReason 不能为空!");
            }
        }
        // 更新报备单状态
        AgentEntity agent = agentService.getById(report.getAgentId());
        if (agent == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "代理商已被删除！");
        }
        if (dto.getIsApprove()) {
            // 认可到已完成状态
            report.setStatus(ReportStatusEnum.SUCCESS.getCode());
            // 更新完成时间
            report.setTransactionDate(LocalDate.now());
            // 安装地址更新
            report.setInstallAddress(dto.getInstallAddress());
            // 审批日志
            reportFlowService.addFlow(report.getId(), "已成交", "代理商[" + sysUserService.getById(report.getCreateUser()).getRealName() + "]与客户确认了成交", 1);
            // 发送消息
            messageService.sendMessage(MsgTemplateEnum.H,
                    report.getId(),
                    null,
                    Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                    localDateFormatter.format(report.getTransactionDate()))
                            .collect(Collectors.toList()),
                    "已成交");
            // 成交客户
            customerService.success(report.getCustomerId());
        } else {
            // 不认可到已失效状态
            report.setStatus(ReportStatusEnum.FAIL.getCode());
            // 更新不认可原因
            report.setInvalidSource("报备未成交");
            report.setInvalidReason(dto.getInvalidReason());

            // 审批日志
            reportFlowService.addFlow(report.getId(), "客户不认可", dto.getInvalidReason(), 2);
            // 发送消息
            messageService.sendMessage(MsgTemplateEnum.I,
                    report.getId(),
                    null,
                    Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                    dateFormatter.format(report.getCreateTime()))
                            .collect(Collectors.toList())
                    , "未成交");

            // 失效客户
            // customerService.invalid(report.getCustomerId());
        }

        // 2024.06.26 ad by lb 以下三个节点更新 商谈中变更到下一状态时间  成交确认(客户认可、客户不认可)/报备逾期/PC端的商谈中订单终止
        report.setDiscussEndDate(LocalDate.now());

        super.updateById(report);// 更新报备单信息

        // 重新添加产品信息
        List<Long> productIds = dto.getProducts().stream().map(ReportProductDTO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(productIds)) {
            // 删除产品信息
            reportProductMapper.deleteByReportId(dto.getId());
            List<ProductInfoEntity> products = productInfoMapper.selectBatchIds(productIds);
            List<ReportProductEntity> productList = new ArrayList<>(products.size());
            products.forEach(p -> {
                ReportProductEntity product = new ReportProductEntity();
                product.setId(null);
                product.setReportId(dto.getId());
                product.setCode(p.getCode());
                product.setProductId(p.getId());
                product.setProductTypeId(p.getProductTypeId());
                product.setName(p.getName());
                product.setPrice(p.getPrice());
                product.setIntroduce(p.getIntroduce());
                product.setImageDetailFileId(p.getImageDetailFileId());
                product.setRemark(p.getRemark());
                product.setManualFileId(p.getManualFileId());
                product.setCreateUser(dto.getUserId());
                product.setNumber(dto.getProducts().stream().filter(t -> t.getId().equals(p.getId())).findFirst().get().getNumber());
                productList.add(product);
            });

            // 批量设置书名号前缀
            AgentVO userAgent = appUserMapper.getAgentInfo(dto.getUserId());
            setCertificateCode(userAgent, productList);

            // 批量保存产品快照信息
            reportProductService.saveBatch(productList);
        }
        return true;
    }

    @Override
    public List<String> getNotApproveReason() {
        LambdaQueryWrapper<Config> queryWrapper = new LambdaQueryWrapper<Config>();
        queryWrapper
                .eq(Config::getCode, "NOT_APPROVE_REASON")
                .eq(Config::getDelFlag, YesOrNotEnum.N.getCode());
        Config config = configService.getOne(queryWrapper);
        return Arrays.asList(config.getValue().split(","));
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public boolean delay(ReportDTO dto) {
        if (dto.getUserId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "userId不能为空");
        if (dto.getId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "id不能为空");
        if (dto.getDelayDate() == null) throw new BusinessException(BUSINESS_EXCEPTION, "delayDate不能为空");
        if (dto.getDelayReason() == null) throw new BusinessException(BUSINESS_EXCEPTION, "delayReason不能为空");
        if (CollectionUtils.isEmpty(dto.getDelayFileIds()))
            throw new BusinessException(BUSINESS_EXCEPTION, "delayFileIds不能为空");

        // 获取当前报备单信息
        ReportEntity report = super.getById(dto.getId());
        if (!Objects.equals(ReportStatusEnum.CONFER.getCode(), report.getStatus())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单状态不在客户商谈中!");
        }
        if (Objects.equals(ReportConferStatusEnum.APPLYING.getCode(), report.getConferStatus())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单延期审批中,请勿重复提交申请!");
        }
        if (Objects.equals(ReportConferStatusEnum.DELAY.getCode(), report.getConferStatus())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单已延期，不可再次延期!");
        }
        // 更新报备单状态
        report.setConferStatus(ReportConferStatusEnum.APPLYING.getCode());
        // 更新延期信息
        report.setDelayDate(dto.getDelayDate());
        report.setDelayReason(dto.getDelayReason());
        report.setDelayApplyTime(new Date());
        report.setDelayCreateUserId(dto.getUserId());
        super.updateById(report);// 更新报备单信息

        // 添加延期附件
        reportDelayFileService.saveBatch(dto.getDelayFileIds().stream().map(t -> {
            ReportDelayFileEntity reportFile = new ReportDelayFileEntity();
            reportFile.setReportId(dto.getId());
            reportFile.setFileId(t);
            reportFile.setCreateUser(dto.getUserId());
            return reportFile;
        }).collect(Collectors.toList()));

        // 审批日志
        reportFlowService.addFlow(report.getId(), "申请延期", dto.getDelayReason(), 3);

        // 发送消息
        AgentEntity agent = agentService.getById(report.getAgentId());
        if (agent == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "代理商已被删除！");
        }
        messageService.sendMessage(MsgTemplateEnum.E,
                report.getId(),
                null,
                Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                dateFormatter.format(report.getDelayApplyTime()))
                        .collect(Collectors.toList()),
                "已申请报备延期");
        return true;
    }

    @Override
    public ReportVO findDetail(Long id, Long userId) {
        ReportEntity reportEntity = super.getById(id);
        ReportVO vo = ConvertUtil.turn(reportEntity, ReportVO.class);

        if (reportEntity != null) {
            // 获取报备单产品信息
            /*LambdaQueryWrapper<ReportProductEntity> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(ReportProductEntity::getReportId, id);
            List<ReportProductEntity> products = reportProductService.list(queryWrapper);*/
            LambdaQueryWrapper<ReportProductEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(ReportProductEntity.class, info -> !info.getColumn().equals("introduce"))
                    .eq(ReportProductEntity::getReportId, id);
            List<ReportProductEntity> products = reportProductService.list(queryWrapper);
            if (CollectionUtils.isEmpty(products)) {
                vo.setProducts(new ArrayList<>());
            } else {
                List<ReportProductVO> productList = ConvertUtil.turn(products, ReportProductVO.class);
                productList.forEach(p -> {
                    p.setImageDetailFileUrl(env.getProperty("file-path") + p.getImageDetailFileId());
                });
                vo.setProducts(productList);
            }
            vo.getProducts().forEach(p -> {
                p.setId(p.getProductId());
            });

            // 设置动态配置
            List<Config> configs = findConfig();
            //报备有效期提前展示延期按钮天数
            int REPORT_END_BUTTON = Integer.parseInt(configs.stream().filter(c -> c.getCode().equals("REPORT_END_BUTTON")).findFirst().get().getValue());
            // 报备有效期提前提醒天数
            int REPORT_END_REMIND = Integer.parseInt(configs.stream().filter(c -> c.getCode().equals("REPORT_END_REMIND")).findFirst().get().getValue());
            // 判断是否该展示申请延期按钮
            vo.setIsShowDelay(
                    !vo.getConferStatus().equals(ReportConferStatusEnum.REFUSE.getCode())
                            && vo.getExpirationDateEnd() != null
                            && (vo.getExpirationDateEnd().minusDays(REPORT_END_BUTTON).isBefore(LocalDate.now())
                            || vo.getExpirationDateEnd().minusDays(REPORT_END_BUTTON).isEqual(LocalDate.now()))
                            && Objects.equals(vo.getConferStatus(), ReportConferStatusEnum.CONFERING.getCode()));
            // 判断是否该延期提醒
            if (vo.getStatus().equals(ReportStatusEnum.CONFER.getCode())) {
                vo.setIsAlarm(vo.getExpirationDateEnd() != null
                        && (vo.getExpirationDateEnd().minusDays(REPORT_END_REMIND).isBefore(LocalDate.now())
                        || vo.getExpirationDateEnd().minusDays(REPORT_END_REMIND).isEqual(LocalDate.now())));
            } else {
                vo.setIsAlarm(false);
            }

            ReportDTO dto = new ReportDTO();
            dto.setUserId(userId);
            extracted(dto);
            if (dto.getRoleId() == 4) {
                // 添加是否是自己或者自己下属创建但报备单标识
                List<Long> userIds = reportMapper.queryOurUserIds(userId);
                vo.setOurReport(userIds.contains(reportEntity.getCreateUser()));
            } else {
                vo.setOurReport(true);
            }
        }
        return vo;
    }

    @Override
    public List<ReportFlowVO> getFlow(Long id) {
        if (id == null) throw new BusinessException(BUSINESS_EXCEPTION, "id不能为空");

        // 查询报备单流程信息
        LambdaQueryWrapper<ReportFlowEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ReportFlowEntity::getReportId, id);
        queryWrapper.orderByAsc(ReportFlowEntity::getCreateTime);
        List<ReportFlowEntity> list = reportFlowService.list(queryWrapper);

        if (CollectionUtils.isNotEmpty(list)) {
            return ConvertUtil.turn(list, ReportFlowVO.class);
        } else {
            return new ArrayList<>();
        }
    }

    @Override
    public Integer reportCount(Long userId) {
        ReportDTO dto = new ReportDTO();
        dto.setUserId(userId);
        //小程序：首页报备中心数量，取报备中的、客户商谈中、已成交的总数
        dto.setStatus(12);
        dto.setCertificateStatus(1);//待登记书号的
        return reportMapper.reportCount(dto);
    }


    private String getNextReportCode() {
        LambdaQueryWrapper<Config> queryWrapper = new LambdaQueryWrapper<Config>();
        queryWrapper
                .eq(Config::getCode, "REPORT_CODE")
                .eq(Config::getDelFlag, YesOrNotEnum.N.getCode());
        Config config = configService.getOne(queryWrapper);
        String value = config.getValue();
        String[] list = value.split("-");
        String pre = list[0];
        String date = list[1];
        String number = list[2];

        // 本次使用的编码
        String code = "";

        // 当前日期和配置日期相同
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        // 格式化为字符串
        String currentDateString = now.format(formatter);
        if (currentDateString.equals(date)) {
            code = pre + "-" + date + "-" + incrementFourDigitString(number);
        } else {
            code = pre + "-" + currentDateString + "-" + "0001";
        }

        // 讲当前编码持久化到数据库配置
        config.setValue(code);
        configService.updateById(config);
        return code;
    }


    /**
     * 四位字符串+1补0
     *
     * @param current
     * @return
     */
    public String incrementFourDigitString(String current) {
        int number = Integer.parseInt(current);
        number++; // 增加1
        String incremented = String.format("%04d", number); // 格式化输出为始终四位的字符串，不足部分前面补0
        return incremented;
    }


    /*以下是web端方法，少数可能存在复用------------------------------------------------*/
    @Override
    public Map<String, Object> findPage(ReportDTO dto) {
        Integer pageNo = dto.getPageNo();
        Integer pageSize = dto.getPageSize();
        dto.setUserId(LoginContext.me().getLoginUser().getUserId());
        extracted(dto);
        List<ReportVO> list = reportMapper.findPage(dto);
        Long total = reportMapper.findPageCount(dto);

        // 客户商谈中statusName设置为子状态
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(t -> {
                if (t.getStatus() == 2) {
                    if (t.getConferStatus() == 1) t.setStatusName("商谈中");
                    if (t.getConferStatus() == 2) t.setStatusName("待审核");// 延期申请
                    if (t.getConferStatus() == 3) t.setStatusName("已延期");
                    if (t.getConferStatus() == 4) t.setStatusName("延期已驳回");
                }
                if (StringUtils.isNotEmpty(t.getSellCode())) {
                    t.setStatusName("已出货");
                }
                // 处理productName
                /*if(StringUtils.isNotEmpty(t.getProductName())){
                    t.setProductName(t.getProductName().replace(",","</br>"));
                }*/
            });
        }


        Map<String, Object> map = new HashMap<>();

        // 查询当前页面汇总计数
        if (dto.getStatus() == 1
                || dto.getStatus() == 2
                || (dto.getStatus() == 3 && dto.getCertificateStatus() == 1)) {
            dto.setStatus(1);
            dto.setCertificateStatus(null);
            Long total1 = reportMapper.findPageCount(dto);
            dto.setStatus(2);
            dto.setCertificateStatus(null);
            Long total2 = reportMapper.findPageCount(dto);
            dto.setStatus(3);
            dto.setCertificateStatus(1);
            Long total3 = reportMapper.findPageCount(dto);
            Long pageTotal = total1 + total2 + total3;
            map.put("pageTotal", pageTotal);


            // 报备中数量
            map.put("total1", total1);
            // 需延期审核数量
            dto.setStatus(2);
            dto.setConferStatus(2);
            Long total2new = reportMapper.findPageCount(dto);
            map.put("total2", total2new);
            // 待登记书名号数量
            map.put("total3", total3);
        }

        if ((dto.getStatus() == 3 && dto.getCertificateStatus() == 2)
                || dto.getStatus() == 4 || dto.getStatus() == 5) {
            dto.setStatus(3);
            dto.setCertificateStatus(2);
            Long total1 = reportMapper.findPageCount(dto);
            dto.setStatus(4);
            dto.setCertificateStatus(null);
            Long total2 = reportMapper.findPageCount(dto);
            dto.setStatus(5);
            dto.setCertificateStatus(null);
            Long total3 = reportMapper.findPageCount(dto);

            Long pageTotal = total1 + total2 + total3;
            map.put("pageTotal", pageTotal);

            // 已完成数量
            map.put("total1", total1);
            // 已失效数量
            map.put("total2", total2);
            // 已出货数量
            map.put("total3", total3);


        }

        map.put("page", PageResultFactory.createPageResult(list, total, pageSize, pageNo));
        return map;
    }

    private void extracted(ReportDTO dto) {
        SysUserRequest sysUserRequest = new SysUserRequest();
        sysUserRequest.setUserId(dto.getUserId());
        SysUserDTO currentUser = sysUserService.detail(sysUserRequest);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(currentUser.getGrantRoleIdList())) {
            return;
        }
        Long roleId = currentUser.getGrantRoleIdList().get(0);
        if (ProjectConstants.ROLE_ID_BMSH_MANAGER.equals(roleId)) {
            dto.setRoleId(1);
        } else if (ProjectConstants.ROLE_ID_BMSH_YG.equals(roleId)) {
            dto.setRoleId(2);
        } else if (ProjectConstants.ROLE_ID_AGENT_MANAGER.equals(roleId)) {
            dto.setRoleId(3);
        } else if (ProjectConstants.ROLE_ID_JL.equals(roleId)) {
            dto.setRoleId(4);
        } else if (ProjectConstants.ROLE_ID_YG.equals(roleId)) {
            dto.setRoleId(5);
        }
    }

    @Override
    public ReportVO getWebDetail(Long id) {
        ReportVO report = reportMapper.getWebDetail(id);

        // 获取报备单产品信息
        List<ReportProductVO> products = reportProductService.findListByReportId(id);
        if (CollectionUtils.isNotEmpty(products)) {
            // 加和所有的number
            Integer totalCount = products.stream().mapToInt(ReportProductVO::getNumber).sum();
            products.forEach(v -> {
                v.setTotalCount(totalCount);
            });
        }
        report.setProducts(products);

        // 获取报备单附件列表
        LambdaQueryWrapper<ReportDelayFileEntity> fileQueryWrapper = Wrappers.lambdaQuery();
        fileQueryWrapper.eq(ReportDelayFileEntity::getReportId, id);
        List<ReportDelayFileEntity> files = reportDelayFileService.list(fileQueryWrapper);
        if (CollectionUtils.isNotEmpty(files)) {
            // 收集files的fileId
            List<Long> fileIds = files.stream().map(ReportDelayFileEntity::getFileId).collect(Collectors.toList());
            // 从sysFileInfo 中获取文件信息
            LambdaQueryWrapper<SysFileInfo> sysFileQueryWrapper = Wrappers.lambdaQuery();
            sysFileQueryWrapper.in(SysFileInfo::getFileId, fileIds);
            List<SysFileInfo> sysFileInfos = sysFileInfoService.list(sysFileQueryWrapper);
            List<ReportDelayFileVO> delayFiles = ConvertUtil.turn(files, ReportDelayFileVO.class);
            delayFiles.forEach(v -> {
                // 设置文件url
                v.setFileUrl(env.getProperty("file-path-preview") + v.getFileId());
                // 从sysFileInfo 中获取文件的后缀
                SysFileInfo sysFileInfo = sysFileInfos.stream().filter(f -> f.getFileId().equals(v.getFileId())).findFirst().orElse(null);
                if (sysFileInfo != null) {
                    v.setFileExt(sysFileInfo.getFileSuffix());
                    v.setFileName(sysFileInfo.getFileOriginName());

                }
            });
            report.setDelayFiles(delayFiles);
        }
        return report;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public Boolean approve(ReportDTO dto) {
        // 参数校验
        Integer action = dto.getAction();
        String reason = dto.getReason();
        if (dto.getId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "id不能为空");
        if (action == null) throw new BusinessException(BUSINESS_EXCEPTION, "action不能为空");
        if (action == 2 && StringUtils.isEmpty(reason))
            throw new BusinessException(BUSINESS_EXCEPTION, "请输入驳回原因");
        if (action == 3 && StringUtils.isEmpty(reason))
            throw new BusinessException(BUSINESS_EXCEPTION, "请输入终止原因");
        if (action == 4 && StringUtils.isEmpty(reason))
            throw new BusinessException(BUSINESS_EXCEPTION, "请输入复核通过原因");

        // 获取报备单信息
        ReportEntity report = super.getById(dto.getId());
        AgentEntity agent = agentService.getById(report.getAgentId());
        if (agent == null) {
            throw new BusinessException(BUSINESS_EXCEPTION, "代理商已被删除！");
        }
        if (action == 1) {
            //审批通过
            if (Objects.equals(ReportStatusEnum.APPLYING.getCode(), report.getStatus())) {
                // 校验当前客户，是否存在客户商谈中，若存在则提示不可发起
                if (checkCustomerHasReport2(report.getCustomerId()))
                    throw new BusinessException(BUSINESS_EXCEPTION, "客户存在商谈中的报备单，此报备单暂不可审批！");

                // 报备中
                report.setStatus(ReportStatusEnum.CONFER.getCode());
                report.setApproveDate(LocalDate.now());
                report.setApproveUser(LoginContext.me().getLoginUser().getUserId());
                // 审批日志
                reportFlowService.addFlow(report.getId(), "客户商谈中", "客户[" + report.getCustomerName() + "]正在与代理商谈", 1);
                // 发送消息
                messageService.sendMessage(MsgTemplateEnum.B,
                        report.getId(),
                        null,
                        Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                        localDateFormatter.format(report.getExpirationDateEnd()))
                                .collect(Collectors.toList()),
                        "通过");
            } else if (Objects.equals(ReportStatusEnum.CONFER.getCode(), report.getStatus())
                    && Objects.equals(ReportConferStatusEnum.APPLYING.getCode(), report.getConferStatus())) {
                // 延期审批
                report.setConferStatus(ReportConferStatusEnum.DELAY.getCode());
                report.setDelayPassTime(DateUtil.date());
                report.setDelayPassUserId(LoginContext.me().getLoginUser().getUserId());
                report.setExpirationDateEnd(report.getDelayDate());
                // 审批日志
                reportFlowService.addFlow(report.getId(), "客户商谈中", "客户[" + report.getCustomerName() + "]正在与代理商谈", 1);

                // 发送消息
                messageService.sendMessage(MsgTemplateEnum.F,
                        report.getId(),
                        null,
                        Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                        localDateFormatter.format(report.getDelayDate()))
                                .collect(Collectors.toList()),
                        "延期通过");
            } else {
                throw new BusinessException(BUSINESS_EXCEPTION, "报备单当前状态无需审批");
            }

        } else if (action == 2) {
            //审批拒绝
            if (Objects.equals(ReportStatusEnum.APPLYING.getCode(), report.getStatus())) {
                // 报备中
                report.setStatus(ReportStatusEnum.FAIL.getCode());// 失效
                report.setInvalidSource("审核未通过");
                report.setInvalidReason(reason);
                // 审批日志
                reportFlowService.addFlow(report.getId(), "审核未通过", reason, 2);
                // 发送消息
                messageService.sendMessage(MsgTemplateEnum.C,
                        report.getId(),
                        null,
                        Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                        localDateFormatter.format(report.getExpirationDateEnd()))
                                .collect(Collectors.toList()),
                        "驳回(" + reason + ")");
            } else if (Objects.equals(ReportStatusEnum.CONFER.getCode(), report.getStatus())
                    && Objects.equals(ReportConferStatusEnum.APPLYING.getCode(), report.getConferStatus())) {
                // 延期审批
                report.setConferStatus(ReportConferStatusEnum.REFUSE.getCode());
                report.setDelayPassTime(DateUtil.date());
                report.setDelayPassUserId(LoginContext.me().getLoginUser().getUserId());

                // 审批日志
                reportFlowService.addFlow(report.getId(), "申请延期被驳回", reason, 2);
                // 发送消息
                messageService.sendMessage(MsgTemplateEnum.G,
                        report.getId(),
                        null,
                        Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                        localDateFormatter.format(report.getDelayDate()))
                                .collect(Collectors.toList()),
                        "延期驳回(" + reason + ")");
            } else {
                throw new BusinessException(BUSINESS_EXCEPTION, "报备单当前状态无需拒绝");
            }

            // 失效客户
            // customerService.invalid(report.getCustomerId());
        } else if (action == 3) {
            //终止
            if (report.getStatus().equals(ReportStatusEnum.FAIL.getCode())) {
                throw new BusinessException(BUSINESS_EXCEPTION, "报备单已失效");
            }

            // 2024.06.26 ad by lb 以下三个节点更新 商谈中变更到下一状态时间  成交确认(客户认可、客户不认可)/报备逾期/PC端的商谈中订单终止
            if (report.getStatus().equals(ReportStatusEnum.CONFER.getCode())) {
                report.setDiscussEndDate(LocalDate.now());
            }

            report.setStatus(ReportStatusEnum.FAIL.getCode());
            report.setInvalidSource("报备单被终止");
            report.setInvalidReason(reason);

            // 失效客户
            // customerService.invalid(report.getCustomerId());

            // 审批日志
            reportFlowService.addFlow(report.getId(), "报备单被终止", reason, 2);
            // 发送消息
            messageService.sendMessage(MsgTemplateEnum.L,
                    report.getId(),
                    null,
                    Stream.of(agent.getName(), report.getCustomerName(), report.getCode(),
                                    reason)
                            .collect(Collectors.toList()),
                    "订单已被BMSH管理者终止");
        } else if (action == 4) {
            //复核
            if (!report.getStatus().equals(ReportStatusEnum.FAIL.getCode())) {
                throw new BusinessException(BUSINESS_EXCEPTION, "报备单不是已失效状态,不可以复核");
            }

            // 报备单状态改为商谈中
            report.setStatus(ReportStatusEnum.CONFER.getCode());
            // 重置部分需要清空的数据
            report.setDiscussEndDate(null);
            //report.setInvalidSource("报备单被终止");
            //report.setInvalidReason(reason);
            // 审批日志
            reportFlowService.addFlow(report.getId(), "人工复核通过", reason, 1);
        } else {
            throw new BusinessException(BUSINESS_EXCEPTION, "action不合法");
        }
        return super.updateById(report);// 更新报备单信息
    }


    @Override
    public Boolean fixCerCode(ReportDTO dto) {
        if (dto.getId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "id不能为空");

        // 查询包被单产品信息
        ReportProductEntity products = reportProductService.getById(dto.getId());
        ReportEntity report = this.getById(products.getReportId());

        if (!report.getStatus().equals(ReportStatusEnum.SUCCESS.getCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "非已成交报备单不可以登记书名号");
        }
        if (report.getCertificateStatus().equals(CertificateStatusEnum.YES.getCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单-书名号已登记");
        }
        if (products.getCertificateStatus().equals(CertificateStatusEnum.YES.getCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "产品-书名号已登记");
        }

        // 补全书名号
        products.setCertificateCode(products.getCertificateCode() + "-" + dto.getCerCode());
        products.setCertificateStatus(CertificateStatusEnum.YES.getCode());
        reportProductService.updateById(products);
        return true;
    }

    @Override
    public Boolean fixSellCode(ReportDTO dto) {
        if (dto.getId() == null) throw new BusinessException(BUSINESS_EXCEPTION, "id不能为空");
        // 查询包被单产品信息
        ReportEntity report = this.getById(dto.getId());
        if (StringUtils.isEmpty(dto.getSellCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "设备序列号不能为空");
        }
        report.setSellCode(dto.getSellCode());
        this.updateById(report);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    public Boolean confirmCerCode(ReportDTO dto) {
        ReportEntity reportNow = this.getById(dto.getId());
        if (reportNow.getCertificateStatus().equals(CertificateStatusEnum.YES.getCode())) {
            throw new BusinessException(BUSINESS_EXCEPTION, "报备单-书名号已登记");
        }

        // 更新报备单状态 查询所有报备单产品
        //LambdaQueryWrapper<ReportProductEntity> queryWrapper = Wrappers.lambdaQuery(ReportProductEntity.class)
        //      .eq(ReportProductEntity::getReportId, dto.getId())
        //    .eq(ReportProductEntity::getDelFlag, "N")
        //  .eq(ReportProductEntity::getCertificateStatus, CertificateStatusEnum.NO.getCode());
        // 全部补全书名号之后 更新报备单书名号状态
        //List<ReportProductEntity> unFixproductList = reportProductService.list(queryWrapper);
        //if (CollectionUtils.isEmpty(unFixproductList)) {
        ReportEntity report = new ReportEntity();
        report.setId(dto.getId());
        report.setCertificateStatus(CertificateStatusEnum.YES.getCode());
        this.updateById(report);
        // 重新获取report
        report = this.getById(report.getId());


        // 更新客户为成交客户
        /*CustomerEntity customer = new CustomerEntity();
        customer.setId(super.getById(dto.getId()).getCustomerId());
        customer.setCustomerStatus(2);// 成交客户
        customer.setTransactionDate(LocalDate.now());// 成交日期
        customerService.updateById(customer);*/

        // 审批日志
        reportFlowService.addFlow(report.getId(), "证明书号", "平台[" + sysUserService.getById(LoginContext.me().getLoginUser().getUserId()).getRealName() + "]生成了证明书号", 4);
        // 发送消息
        messageService.sendMessage(MsgTemplateEnum.J,
                report.getId(),
                null,
                Stream.of(report.getCustomerName(), report.getCode(),
                                localDateFormatter.format(report.getTransactionDate()))
                        .collect(Collectors.toList()),
                "证明书号已填写完成");
        return true;
        //} else {
        //    throw new BusinessException(BUSINESS_EXCEPTION, "请先补全所有的书名号信息!");
        //}
    }


}
